﻿using System;
using System.Net.Sockets;
using System.Collections;
using System.Threading;
using System.IO;
using log4net;

public class Client
{
    readonly ILog log = LogManager.GetLogger(typeof(Client));
    readonly TcpClient socketForServer;
    readonly Queue toReceive;
    readonly Queue toSend;
    readonly Object pollLock;
    readonly Object pushLock;
    private Boolean dispose = false;

    public Client(String host, int port)
    {
        try
        {
            socketForServer = new TcpClient(host, port);
            log.Info("Created socket " + socketForServer.ToString());

            toSend = new Queue();
            toReceive = new Queue();
            pollLock = new Object();
            pushLock = new Object();
            connect();
        }
        catch (Exception ex)
        {
            log.Error("Can't create to the socket ", ex);
        }
    }

    public void connect()
    {
        Thread job = new Thread(BridgeSocketAndQueue);
        job.IsBackground = true;
        job.Start();
        log.Info("Connection thread started");
    }

    public void shutdown()
    {
        dispose = true;
        try
        {
            socketForServer.Close();
        }
        catch (Exception ex)
        {
            log.Error("Error shutting down socket", ex);
        }
    }

    private void BridgeSocketAndQueue() {
        NetworkStream networkStream = socketForServer.GetStream();
        StreamReader streamReader = new StreamReader(networkStream);
        StreamWriter streamWriter = new StreamWriter(networkStream);
        while (true && !dispose)
        {
            lock (pushLock)
            {
                if (toReceive.Count == 0)
                {
                    Monitor.Wait(pushLock);
                }
                String msg = (String)toReceive.Dequeue();
                streamWriter.WriteLine(msg);
                streamWriter.Flush();
            }

            lock (pollLock)
            {
                toSend.Enqueue(streamReader.ReadLine());
                Monitor.Pulse(pollLock);
            }
        }
        // Keep it for later use
        //networkStream.Close();
    }


    public String pollMessage()
    {
        while (true)
        {
            lock (pollLock)
            {
                if (toSend.Count == 0)
                {
                    Monitor.Wait(pollLock);
                }
                else
                {
                    return (String)toSend.Dequeue();
                }
            }
        }
    }

    public void pushMessage(String msg) {
        lock (pushLock)
        {
            toReceive.Enqueue(msg);
            Monitor.Pulse(pushLock);
        }
    }

}